﻿using Prism.Commands;
using Prism.Navigation;
using Prism.Regions;
using Quartz;
using Quartz.Impl.Matchers;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ZYing.QPanel.ViewModels
{
    public class JobsViewModel : NavigationViewModelBase
    {
        public JobsViewModel(IScheduler scheduler)
        {
            Scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler));
            this.ReloadCommand = new DelegateCommand(RunReload);
            this.RunReload();
            Run(this.CancellationTokenSource.Token);
        }
        private async void RunReload()
        {
            await this.Reload();
        }

        public IScheduler Scheduler { get; }

        private string _keyword;

        public string Keyword
        {
            get { return _keyword; }
            set { if (SetProperty(ref _keyword, value)) this.RunReload(); }
        }
        private string _group;

        public string Group
        {
            get { return _group; }
            set { if (SetProperty(ref _group, value)) this.RunReload(); }
        }
        public ObservableCollection<string> Groups { get; } = new ObservableCollection<string>();
        public ObservableCollection<JobItemViewModel> Jobs { get; } = new ObservableCollection<JobItemViewModel>();
        public DelegateCommand ReloadCommand { get; }
        private async Task<List<JobItemViewModel>> GetAllJobs(GroupMatcher<JobKey> matcher)
        {
            var ret = new List<JobItemViewModel>();
            var keys = await Scheduler.GetJobKeys(matcher);
            foreach (var key in keys)
            {
                try
                {
                    var jobDetail = await Scheduler.GetJobDetail(key);
                    var job = new JobItemViewModel(key, this);
                    job.Read(jobDetail);
                    ret.Add(job);
                }
                catch (JobPersistenceException)
                {
                    if (!await Scheduler.CheckExists(key))
                    {
                        await Scheduler.DeleteJob(key);
                        Helpers.NotifyHelper.Warn($"自动删除不存在的任务:{key}");
                    }
                }
            }
            return ret;
        }
        public async Task Reload()
        {
            var groups = await Scheduler.GetJobGroupNames();
            foreach (var name in groups)
            {
                if (Groups.Contains(name)) continue;
                Groups.Add(name);
            }
            GroupMatcher<JobKey> matcher = GroupMatcher<JobKey>.AnyGroup();
            if (!string.IsNullOrWhiteSpace(this.Group))
            {
                matcher = GroupMatcher<JobKey>.GroupEquals(this.Group);
            }
            var allJobs = await GetAllJobs(matcher);
            List<JobItemViewModel> showJobs = null;
            if (!string.IsNullOrWhiteSpace(this.Keyword))
            {
                showJobs = new List<JobItemViewModel>(allJobs.Count);
                foreach (var job in allJobs)
                {
                    var key = $"{job.Group}_{job.Key}_{job.Class}";
                    if (key.IndexOf(this.Keyword, StringComparison.OrdinalIgnoreCase) >= 0)
                    {
                        showJobs.Add(job);
                    }
                }
            }
            else
            {
                showJobs = allJobs;
            }

            var dic = Jobs.ToDictionary(i => i.Key, i => i);
            foreach (var job in showJobs)
            {
                if (dic.TryGetValue(job.Key, out var exists))
                {
                    exists.Merge(job);
                    dic.Remove(job.Key);
                }
                else
                {
                    Jobs.Add(job);
                }
            }

            if (dic.Count > 0)
            {
                foreach (var job in dic.Values)
                {
                    this.Jobs.Remove(job);
                }
            }
            await RefreshStatus();
        }

        public async Task RefreshStatus()
        {
            //做一个拷贝，防止循环更新
            var josb = this.Jobs.ToArray();
            foreach (var job in josb)
            {
                await job.Refresh(this.Scheduler);
            }
        }

        private async void Run(CancellationToken cancellationToken)
        {
            while (true)
            {
                if (cancellationToken.IsCancellationRequested) break;
                if (this.IsActive)
                {
                    try
                    {
                        await RefreshStatus();
                    }
                    catch (Exception e)
                    {
                        Trace.WriteLine(e);
                    }
                }
                await Task.Delay(1000);
            }
        }
    }
}
